const crypto = require('crypto');

/**
 * User class representing a chat room participant
 */
class User {
    constructor(id, nickname, websocket = null) {
        this.id = id;
        this.nickname = nickname;
        this.websocket = websocket;
        this.joinedAt = new Date();
        this.isOnline = true;
        this.lastActivity = new Date();
        this.sessionToken = null; // For session management
    }

    /**
     * Update user's last activity timestamp
     */
    updateActivity() {
        this.lastActivity = new Date();
    }

    /**
     * Set user as offline
     */
    setOffline() {
        this.isOnline = false;
        this.websocket = null;
    }

    /**
     * Get user info for client transmission
     */
    toJSON() {
        return {
            id: this.id,
            nickname: this.nickname,
            joinedAt: this.joinedAt,
            isOnline: this.isOnline,
            lastActivity: this.lastActivity
        };
    }
}

/**
 * Message class representing a chat message
 */
class Message {
    constructor(userId, content, type = 'text') {
        this.id = this.generateId();
        this.userId = userId;
        this.content = content;
        this.type = type; // text, system, join, leave
        this.timestamp = new Date();
    }

    /**
     * Generate unique message ID
     */
    generateId() {
        return crypto.randomBytes(8).toString('hex');
    }

    /**
     * Create a system message
     */
    static createSystemMessage(content) {
        return new Message('system', content, 'system');
    }

    /**
     * Create a user join message
     */
    static createJoinMessage(userId, nickname) {
        return new Message(userId, `${nickname} joined the room`, 'join');
    }

    /**
     * Create a user leave message
     */
    static createLeaveMessage(userId, nickname) {
        return new Message(userId, `${nickname} left the room`, 'leave');
    }

    /**
     * Get message info for client transmission
     */
    toJSON() {
        return {
            id: this.id,
            userId: this.userId,
            content: this.content,
            type: this.type,
            timestamp: this.timestamp
        };
    }
}

/**
 * Room class representing a chat room
 */
class Room {
    constructor(id, name, password = null, maxUsers = 50) {
        this.id = id;
        this.name = name;
        this.password = password;
        this.maxUsers = maxUsers;
        this.members = new Map(); // userId -> User
        this.messages = [];
        this.createdAt = new Date();
        this.inviteCode = this.generateInviteCode();
        this.messageHistory = 100; // Maximum messages to keep in memory
    }

    /**
     * Generate unique invite code for the room
     */
    generateInviteCode() {
        return crypto.randomBytes(6).toString('hex').toUpperCase();
    }

    /**
     * Generate unique room ID
     */
    static generateRoomId() {
        return crypto.randomBytes(8).toString('hex');
    }

    /**
     * Add a user to the room
     */
    addUser(user) {
        if (this.members.size >= this.maxUsers) {
            throw new Error('Room is full');
        }
        
        this.members.set(user.id, user);
        
        // Add join message
        const joinMessage = Message.createJoinMessage(user.id, user.nickname);
        this.addMessage(joinMessage);
        
        return user;
    }

    /**
     * Remove a user from the room
     */
    removeUser(userId) {
        const user = this.members.get(userId);
        if (user) {
            this.members.delete(userId);
            
            // Add leave message
            const leaveMessage = Message.createLeaveMessage(userId, user.nickname);
            this.addMessage(leaveMessage);
            
            return user;
        }
        return null;
    }

    /**
     * Add a message to the room
     */
    addMessage(message) {
        this.messages.push(message);
        
        // Keep only recent messages to prevent memory overflow
        if (this.messages.length > this.messageHistory) {
            this.messages = this.messages.slice(-this.messageHistory);
        }
        
        return message;
    }

    /**
     * Get user by ID
     */
    getUser(userId) {
        return this.members.get(userId);
    }

    /**
     * Get all online users
     */
    getOnlineUsers() {
        return Array.from(this.members.values()).filter(user => user.isOnline);
    }

    /**
     * Check if room has password protection
     */
    hasPassword() {
        return this.password !== null && this.password !== '';
    }

    /**
     * Validate room password
     */
    validatePassword(inputPassword) {
        if (!this.hasPassword()) {
            return true;
        }
        return this.password === inputPassword;
    }

    /**
     * Check if room is empty
     */
    isEmpty() {
        return this.getOnlineUsers().length === 0;
    }

    /**
     * Get room info for client transmission
     */
    toJSON() {
        return {
            id: this.id,
            name: this.name,
            hasPassword: this.hasPassword(),
            memberCount: this.getOnlineUsers().length,
            maxUsers: this.maxUsers,
            createdAt: this.createdAt,
            inviteCode: this.inviteCode
        };
    }

    /**
     * Get detailed room info including members and messages
     */
    getDetailedInfo() {
        return {
            ...this.toJSON(),
            members: this.getOnlineUsers().map(user => user.toJSON()),
            messages: this.messages.slice(-50).map(msg => msg.toJSON()) // Last 50 messages
        };
    }
}

module.exports = {
    User,
    Message,
    Room
};